 
//
//  Ball.cpp
//  Demo
//
//  Created by CG on 13-10-3.
//
//

#include "Ball.h"


Ball::Ball()
:BaseObject::BaseObject()
{
    m_ballState = BallStateNone;
    m_objectClassification = ObjectClassification_Ball;
}


Ball::~Ball()
{
    
    BaseObject::~BaseObject();
}


void Ball::onEnter()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kBallTouchPriority, false);
	this->scheduleUpdate();
    CCNode::onEnter();
}


void Ball::initWithFileAndType(const char *pszBallFilename, ObjectType objType)
{
    m_objectType = objType;
    
    //ball
    CCSprite* pBallSprite = CCSprite::create(pszBallFilename);
    this->addChild(pBallSprite, kBallZOrder, kBallTag);
    
    //arrow
    CCSprite* arrowSprite = CCSprite::create("./arrow.png");
    this->addChild(arrowSprite, this->getZOrder() + 1, kBallDirectionArrowTag);
    arrowSprite->setVisible(false);
    
    //shoot
    CCSprite* circleSprite = CCSprite::create("./circle.png");
    this->addChild(circleSprite, this->getZOrder() + 1, kShootCircleTag);
    circleSprite->setVisible(false);
	float scale = MaxRangeRadiusForShoot * 2 / circleSprite->getContentSize().width;
    circleSprite->setScale(scale);
    
    CCSprite* rangeSprite = CCSprite::create("./range.png");
    this->addChild(rangeSprite, this->getZOrder() + 1, kShootRangeTag);
    rangeSprite->setOpacity(100.0f);
    rangeSprite->setVisible(false);
    
    //aim
    CCSpriteBatchNode* batchNode = CCSpriteBatchNode::create("./aim.png");
    this->addChild(batchNode, 0, kAimSpriteBatchNodeTag);
    for (int i=0; i<kAimSpriteTotalNumber; ++i)
    {
        CCSprite* pAimSprite = CCSprite::create(batchNode->getTexture());
        this->addChild(pAimSprite, this->getZOrder() + 1);
        pAimSprite->setVisible(false);
        pAimSprite->setScale(0.2f);
        m_aimSpriteList.push_back(pAimSprite);
    }
}



void Ball::SetObjectPosition(const cocos2d::CCPoint &position)
{
    if (this->getChildByTag(kBallTag))
    {
        this->getChildByTag(kBallTag)->setPosition(position);
    }
}
void Ball::SetObjectScale(const float scale)
{
    if (this->getChildByTag(kBallTag))
    {
        this->getChildByTag(kBallTag)->setScale(scale);
    }
}
void Ball::SetObjectRotation(const float fRotation)
{
    if (this->getChildByTag(kBallTag))
    {
        this->getChildByTag(kBallTag)->setRotation(fRotation);
    }
}



void Ball::update(float dt)
{
    if (m_pBody)
    {
        CCSprite* arrowSprite = (CCSprite* )this->getChildByTag(kBallDirectionArrowTag);

		if (m_ballState == BallStateMove &&
            this->getChildByTag(kBallTag) &&
            arrowSprite)
        {
            arrowSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());

			if (m_pBody)
            {
                b2Vec2 ballVelocity = m_pBody->GetLinearVelocity();
                float newRotation = -1 * CC_RADIANS_TO_DEGREES( ccpToAngle(CCPointMake(ballVelocity.x, ballVelocity.y)) );
                arrowSprite->setRotation( newRotation);
            }
            arrowSprite->setVisible(true);
        }

		CCSprite* circleSprite = (CCSprite*)this->getChildByTag(kShootCircleTag);
        if (m_ballState == BallStateShoot &&
            this->getChildByTag(kBallTag) &&
            circleSprite)
        {
            circleSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
            circleSprite->setVisible(true);
        }

		CCSprite* shootRangeSprite = (CCSprite*)this->getChildByTag(kShootRangeTag);
        if (m_ballState == BallStateShoot &&
            shootRangeSprite &&
            shootRangeSprite->isVisible() == true)
        {
            shootRangeSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
        }
    }
}



void Ball::CreateBody(b2World *pWorld)
{
    
    CCSprite* ballSprite = (CCSprite*)this->getChildByTag(kBallTag);
    
    if (ballSprite)
    {
        // Define the dynamic body.
        b2BodyDef bodydef;
        bodydef.type = b2_dynamicBody;
        bodydef.position.Set(ballSprite->getPositionX() / kPTM_RATIO, ballSprite->getPositionY() / kPTM_RATIO);
        bodydef.userData = this;
        
        m_pBody = pWorld->CreateBody(&bodydef);
        
        // Define another box shape for our dynamic body.
        b2CircleShape dynamicBallShape;
        dynamicBallShape.m_radius = ballSprite->boundingBox().size.width * 0.5 / kPTM_RATIO;
        
        // Define the dynamic body fixture.
        b2FixtureDef fixtureDef;
        fixtureDef.shape = &dynamicBallShape;
        fixtureDef.density = 1.0f;
        fixtureDef.friction = 1.0f;
        fixtureDef.restitution = 0.4f;
        m_pBody->CreateFixture(&fixtureDef);
    }
}



bool Ball::IsTouchPointInBall(cocos2d::CCTouch *pTouchPos)
{
    CCPoint touchPos = pTouchPos->locationInView();
    touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);
    
    if (this->getChildByTag(kBallTag))
    {
        return CCRect::CCRectContainsPoint(this->getChildByTag(kBallTag)->boundingBox(), touchPos);
    }
    
    return false;
}

bool Ball::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
    if (BallStateShoot == m_ballState)
    {
        return true;
    }
    
    if (this->IsTouchPointInBall(pTouch))
    {
        m_ballState = BallStateSelected;
        
        return true;
    }
    

    
    m_ballState = BallStateNone;
    return true;
}

void Ball::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
    CCPoint touchPos = pTouch->locationInView();
    touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);
    
    if (BallStateSelected == m_ballState ||
        BallStateMove == m_ballState)
    {
        m_ballState = BallStateMove;
        
        touchPos.x = touchPos.x / kPTM_RATIO;
        
		float distance = touchPos.x - m_pBody->GetPosition().x;
        distance = distance > 2.0f ? 2.0f : distance;
        b2Vec2 force = b2Vec2(distance * MaxForceForMove, 0.0f);
        m_pBody->ApplyForce(force, m_pBody->GetWorldCenter());
        
        return;
    }
    
    if (BallStateShoot == m_ballState)
    {
		CCSprite* shootRangeSprite = (CCSprite*)this->getChildByTag(kShootRangeTag);
        if (shootRangeSprite)
        {
			CCPoint ballPos = CCPointMake( m_pBody->GetPosition().x * kPTM_RATIO,
                                          m_pBody->GetPosition().y * kPTM_RATIO);
            float distanceToBall = ccpDistance(touchPos, ballPos);
            distanceToBall = distanceToBall > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distanceToBall;
            float scale = distanceToBall * 2.0f / shootRangeSprite->getContentSize().width;
            shootRangeSprite->setScale(scale);
            shootRangeSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
            shootRangeSprite->setVisible(true);
            
            CCPoint direction = ccpNormalize(CCPointMake(touchPos.x - ballPos.x,touchPos.y - ballPos.y));
            distanceToBall = distanceToBall > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distanceToBall;
            b2Vec2 force = b2Vec2(direction.x * distanceToBall * MaxForceForShoot / MaxRangeRadiusForShoot,
                                  direction.y * distanceToBall * MaxForceForShoot / MaxRangeRadiusForShoot);
            
			float timeSpace = 0.06f;
            int index = 1;
            b2Vec2 gravity = b2Vec2(Box2DGravity.x, Box2DGravity.y);
            for(list<CCSprite*>::iterator iter=m_aimSpriteList.begin();
                iter != m_aimSpriteList.end();
                ++iter)
            {
                CCSprite* aimSprite = *iter;
                float dt = index * timeSpace;
                if (aimSprite)
                {
                    aimSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
                    aimSprite->setVisible(true);
                    aimSprite->setOpacity(255.0f - 255.0f * index / (kAimSpriteTotalNumber + 1));
                    aimSprite->setPositionX(aimSprite->getPositionX() + kPTM_RATIO * dt * force.x / m_pBody->GetMass());
                    aimSprite->setPositionY(aimSprite->getPositionY() + kPTM_RATIO * dt * force.y / m_pBody->GetMass() + kPTM_RATIO * 0.5 * gravity.y * dt * dt);
                }
                
                index++;
            }
        }
    }
}

void Ball::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
    if (this->getChildByTag(kBallDirectionArrowTag))
    {
        this->getChildByTag(kBallDirectionArrowTag)->setVisible(false);
        m_pBody->ApplyForce(b2Vec2(0.0f, 0.0f), m_pBody->GetWorldCenter());
    }
    
    
    if (BallStateMove == m_ballState)
    {
        m_ballState = BallStateNone;
    }
    
    if (BallStateShoot == m_ballState)
    {
        m_ballState = BallStateNone;
        
		if (this->getChildByTag(kShootCircleTag))
        {
            this->getChildByTag(kShootCircleTag)->setVisible(false);
        }
        if (this->getChildByTag(kShootRangeTag))
        {
            this->getChildByTag(kShootRangeTag)->setVisible(false);
        }
        for(list<CCSprite*>::iterator iter=m_aimSpriteList.begin();
            iter != m_aimSpriteList.end();
            ++iter)
        {
            if (*iter)
            {
                ((CCSprite*)*iter)->setVisible(false);
            }
        }
        
		CCPoint touchPos = pTouch->locationInView();
        touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);
        CCPoint ballPos = CCPointMake(m_pBody->GetPosition().x * kPTM_RATIO,
                                      m_pBody->GetPosition().y * kPTM_RATIO);
        float distance = ccpDistance(touchPos, ballPos);
        CCPoint direction = ccpNormalize(CCPointMake(touchPos.x - ballPos.x,
                                                     touchPos.y - ballPos.y));
        distance = distance > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distance;
        b2Vec2 force = b2Vec2(direction.x * distance * MaxForceForShoot / MaxRangeRadiusForShoot,
                              direction.y * distance * MaxForceForShoot / MaxRangeRadiusForShoot);
//        m_pBallBody->ApplyForce(force, m_pBallBody->GetWorldCenter());
        m_pBody->ApplyLinearImpulse(force, m_pBody->GetWorldCenter());
    }
    
	if (BallStateSelected == m_ballState)
    {
        if (this->IsTouchPointInBall(pTouch))
        {
            m_ballState = BallStateShoot;
        }
        else
        {
            m_ballState = BallStateNone;
        }
    }
}
